/*************************************************
* Title：TinyToolKit
* Author：Opportunity 
* Describe：实现知识库窗口
* 包含知识模块分类，知识点的编写修改保存，知识点检索分类的功能
* CreateTime：2020-07-07 14:56:32
* Version：1.0
* Modify Recorder：
* 2022-05-23 ：升级知识库的功能
*************************************************/

using System;
using System.Collections.Generic;
using System.Reflection;
using TinyToolKit;
using UnityEngine;
using UnityEditor;

namespace TinyToolKitEditor
{
    [Serializable]
    public class InfoMode
    {
        public InfoModeItem[] infoModeItems; 
    }

    [Serializable]
    public class InfoModeItem
    {
        public string infoMode;
        public string[] summaryPaths;
    }

    [Serializable]
    public class Summary
    {
        public string name;
        public SummaryItem[] summaryItems;
    }

    [Serializable]
    public class SummaryItem
    {
        public string title;
        public SummarySubItem[] summarySubItems;
    }

    [Serializable]
    public class SummarySubItem
    {
        public string subTitle;
        public string content;
    }
    
    public class SearchItem
    {
        public InfoMode shaderMode;
        public string category;
        public string title;
        public string content;
    }

    public class TinyInfoLibraryWindow : EditorWindow
    {
        public static TinyInfoLibraryWindow _instance;

        private InfoMode _infoMode;
        private int _curInfoModeIndex;//当前知识种类的下标
        private int _curInfoMenuIndex;//当前知识分类的下标
        private int _oldInfoModeIndex;//上一个知识种类的下标
        private int _oldInfoMenuIndex;//上一个知识分类的下标
        private string[] _curModeNames;//存储所有的知识种类 
        private string[] _curMenuNames;//存储所有的知识分类
        private Dictionary<string, List<Summary>> _allInfoModeSummary;//所有知识种类的所有分类知识，key是InfoMode
        private List<Summary> _curSummaryMap; //存储当前知识种类下的所有分类
        private List<SearchItem> _curAllSummarySubItems; //存储当前知识分类下的所有知识点
        private List<SearchItem> _searchResult;//存储当前搜索的知识点

        private float _leftMenuWidth;
        private string _searchStr;
        private string _oldSearchStr;
        private Vector2 scrollPos;
        private int buildInlastIndex;
        private int shaderGraphlastIndex;
        private bool _isEditorMode;

        public static void ShowWindow()
        {
            _instance = GetWindow<TinyInfoLibraryWindow>();
            _instance.titleContent = new GUIContent("Info Library");
            _instance.Show();
        }

        private void OnEnable()
        {
            _leftMenuWidth = 150;
            _oldInfoModeIndex = -1;

            _allInfoModeSummary = new Dictionary<string, List<Summary>>();
            _searchResult = new List<SearchItem>();
            _curSummaryMap = new List<Summary>();
            _curAllSummarySubItems = new List<SearchItem>();

            ParseModeJson();
        }

        private void OnGUI()
        {
            #region Title Bar
            GUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.Width(position.width));

            _curInfoModeIndex = EditorGUILayout.Popup(_curInfoModeIndex, _curModeNames, EditorStyles.toolbarDropDown, GUILayout.Width(_leftMenuWidth));
            if (_oldInfoModeIndex != _curInfoModeIndex)
            {
                OnSelectedChanged();
                _curInfoMenuIndex = 0;
                ParseSummaryJson(_curInfoModeIndex);
            }

            GUILayout.FlexibleSpace();
            if (_isEditorMode == false && GUILayout.Button(EditorGUIUtility.FindTexture("d_CustomTool"), (GUIStyle)"TE toolbarbutton", GUILayout.MaxWidth(30)))
                _isEditorMode = true;

            if (_isEditorMode && GUILayout.Button(EditorGUIUtility.FindTexture("d_winbtn_win_restore_h"), (GUIStyle)"TE toolbarbutton", GUILayout.MaxWidth(30)))
            {
                _isEditorMode = false;
                //保存当前修改的知识点
                SaveChanges();
            }
            GUILayout.Space(5);
            DrawSearchBox();

            GUILayout.EndHorizontal();
            #endregion

            #region Working Area
            EditorGUILayout.BeginHorizontal();

            //左边菜单
            _curInfoMenuIndex = DrawSelectedMenu(_curInfoMenuIndex, _curMenuNames);
            //右边内容显示
            scrollPos = EditorGUILayout.BeginScrollView(scrollPos,false,false);
            DrawSummary(_curInfoMenuIndex);
            DrawSearchResult();
            EditorGUILayout.EndScrollView();

            EditorGUILayout.EndHorizontal();
            #endregion

            Repaint();
        }

        private void OnDisable() 
        {
            _searchResult.Clear();
            _curSummaryMap.Clear();
            _curAllSummarySubItems.Clear();
            _allInfoModeSummary.Clear();
        }

        private void ParseModeJson()
        {
            TextAsset textAssets = Resources.Load<TextAsset>("InfoLibrary/InfoMode");

            _infoMode = TinyUtility.Json.ToObject<InfoMode>(textAssets.text);
            _curModeNames = new string[_infoMode.infoModeItems.Length];

            for (int i = 0; i < _curModeNames.Length; i++)
            {
                _curModeNames[i] = _infoMode.infoModeItems[i].infoMode;
            }
        }

        //解析知识分类的Json数据表
        private void ParseSummaryJson(int infoModeIndex)
        {
            InfoModeItem modeItem = _infoMode.infoModeItems[infoModeIndex];
            if (_allInfoModeSummary.ContainsKey(modeItem.infoMode))
            {
                _curSummaryMap = _allInfoModeSummary[modeItem.infoMode];
            }
            else
            {
                string[] paths = modeItem.summaryPaths;
                _curMenuNames = new string[paths.Length];
                List<Summary> tempSummaryMap = new List<Summary>();

                for (int i = 0; i < paths.Length; i++)
                {
                    TextAsset textAssets = Resources.Load<TextAsset>(paths[i]);
                    Summary summary = TinyUtility.Json.ToObject<Summary>(textAssets.text);
                    tempSummaryMap.Add(summary);
                }

                _allInfoModeSummary.Add(modeItem.infoMode, tempSummaryMap);
                _curSummaryMap = tempSummaryMap;
            }

            //更新当前知识种类下的所有类别
            //更新当前知识种类下所有的知识点
            _curMenuNames = new string[_curSummaryMap.Count];
            _curAllSummarySubItems.Clear();

            for (int i = 0; i < _curSummaryMap.Count; i++)
            {
                Summary summary = _curSummaryMap[i];
                _curMenuNames[i] = summary.name;

                SummaryItem[] items = summary.summaryItems;
                for (int j = 0; j < items.Length; j++)
                {
                    SummarySubItem[] subItems = items[j].summarySubItems;
                    for (int k = 0; k < subItems.Length; k++)
                    {
                        SearchItem searchItem = new SearchItem
                        {
                            category = summary.name,
                            title = subItems[k].subTitle,
                            content = subItems[k].content
                        };
                        _curAllSummarySubItems.Add(searchItem);
                    }
                }
            }

            SearchSubItems();
            _oldInfoModeIndex = infoModeIndex;
        }

        //当选择知识种类改变时
        private void OnSelectedChanged() 
        {
            //如果当前是编辑模式，则提示是否保存修改
            if (_isEditorMode)
            {
                SaveChanges();
                _isEditorMode = false;
            }
        }

        private void SaveChanges()
        {
            Summary summary = _curSummaryMap[_oldInfoMenuIndex];
            string str = TinyUtility.Json.ToJson(summary);
            string path = _infoMode.infoModeItems[_oldInfoModeIndex].summaryPaths[_oldInfoMenuIndex];
            TextAsset textAssets = Resources.Load<TextAsset>(path);
            string fullPath = AssetDatabase.GetAssetPath(textAssets);
            TinyUtility.File.SaveTextFile(fullPath, str);

            AssetDatabase.Refresh();
        }

        private void DrawLastMenuItem()
        {
            DrawSummaryItemTitle("特别感谢");
            DrawSubItemContent("Hongwei Li", "《Shader Reference 编辑器》");
            DrawSubItemContent("冯乐乐", "《Unity Shader 入门精要》");
            DrawSubItemContent("洪流学堂", "《Shader Graph 节点详解》");
            DrawSubItemContent("郭浩瑜", "《Unity 3D ShaderLab开发实战详解》");
        }

        private int DrawSelectedMenu(int selectedId, string[] menus)
        {
            if (menus == null || menus.Length == 0) return -1;
            
            EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Width(_leftMenuWidth),
                GUILayout.MaxHeight(position.height));
            for (int i = 0; i < menus.Length; i++)
            {
                if (i > 0) EditorGUILayout.BeginHorizontal(new GUIStyle("EyeDropperHorizontalLine"));
                GUILayout.Label(menus[i], new GUIStyle("Label") {fixedHeight = 25, alignment = TextAnchor.MiddleCenter});
                if (i > 0) EditorGUILayout.EndHorizontal();

                Rect rect = GUILayoutUtility.GetLastRect();
                if (selectedId == i)
                    GUI.Box(rect, "", new GUIStyle("SelectionRect"));

                if (Event.current.type == EventType.MouseDown && rect.Contains(Event.current.mousePosition))
                {
                    selectedId = i;
                    Event.current.Use();
                }
            }
            EditorGUILayout.EndVertical();

            return selectedId;
        }

        private void DrawSummary(int curInfoMenuIndex)
        {
            if (curInfoMenuIndex < 0 || curInfoMenuIndex >= _curSummaryMap.Count) return;

            Summary summary = _curSummaryMap[curInfoMenuIndex];
            if (summary == null || _searchStr.IsNullOrEmpty() == false) return;
            
            EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.MaxWidth(position.width - _leftMenuWidth));

            SummaryItem[] summaryItems = summary.summaryItems;

            for (int i = 0; i < summaryItems.Length; i++)
            {
                DrawSummaryItemTitle(summaryItems[i].title);

                SummarySubItem[] subItems = summaryItems[i].summarySubItems;
                for (int j = 0; j < subItems.Length; j++)
                {
                    if (_isEditorMode)
                        DrawSubItemContent(curInfoMenuIndex, i, j);
                    else
                        DrawSubItemContent(subItems[j].subTitle, subItems[j].content);
                }
            }

            EditorGUILayout.EndVertical();

            if (curInfoMenuIndex != _oldInfoMenuIndex)
                OnSelectedChanged();
            _oldInfoMenuIndex = curInfoMenuIndex;
        }

        private string HighLightTitle(string title,string checkStr) 
        {
            string oriTitle = title.Trim();
            string lowerTitle = oriTitle.ToLower();
            string lowerCheckStr = checkStr.Trim().ToLower();
            
            if (lowerCheckStr.IsNullOrEmpty() == false && lowerTitle.Contains(lowerCheckStr))
            {
                int index = lowerTitle.IndexOf(lowerCheckStr, StringComparison.Ordinal);
                string firstStr = oriTitle.Substring(0, index);
                string secondStr = oriTitle.Substring(index, lowerCheckStr.Length);
                string thirdStr = oriTitle.Substring(index + lowerCheckStr.Length, lowerTitle.Length - index - lowerCheckStr.Length);
                return firstStr + "<color=yellow>" + secondStr + "</color>" + thirdStr;
            }

            return title;
        }

        private string SearchField(string value, params GUILayoutOption[] options)
        {
            MethodInfo info = typeof(EditorGUILayout).GetMethod("ToolbarSearchField",BindingFlags.NonPublic | BindingFlags.Static, null,new System.Type[] { typeof(string), typeof(GUILayoutOption[]) }, null);

            if (info != null)
                value = (string)info.Invoke(null, new object[] { value, options });

            return value;
        }

        private void DrawSearchResult()
        {
            if (_searchStr.IsNullOrEmpty() == false)
            {
                if (_searchResult.Count > 0)
                {
                    foreach (var item in _searchResult)
                    {
                        string title = HighLightTitle(item.title, _searchStr);
                        DrawSubItemContent(title, item.content);
                    }
                }
                else
                {
                    DrawSummaryItemTitle($"未查找到\"{_searchStr}\"的相关内容！");
                }
            }
            else if (_searchStr.IsNullOrEmpty())
            {
                _searchResult.Clear();
            }
        }

        private void SearchSubItems() 
        {
            if (_searchStr.IsNullOrEmpty()) return;

            _searchResult.Clear();
            foreach (var item in _curAllSummarySubItems)
            {
                if (item.title.Trim().ToLower().Contains(_searchStr.Trim().ToLower()))
                    _searchResult.Add(item);
            }
        }

        private void DrawSearchBox()
        {
            _searchStr = SearchField(_searchStr, GUILayout.Width(200));

            if (_searchStr.IsNullOrEmpty() == false && _searchStr != _oldSearchStr)
            {
                SearchSubItems();
                _oldSearchStr = _searchStr;
            }
        }

        private void DrawSummaryItemTitle(string title)
        {
            GUIStyle titleStyle = new GUIStyle("label") {fontSize = 18,fontStyle = FontStyle.Bold,alignment = TextAnchor.MiddleCenter};
            EditorGUILayout.LabelField(title, titleStyle,GUILayout.Height(24));
        }

        private void DrawSubItemContent(string title , string message)
        {
            GUIStyle titleStyle = new GUIStyle("label") {fontSize = 14,fontStyle = FontStyle.Bold, richText = true};
            GUIStyle msgStyle = new GUIStyle("label") {wordWrap = true, richText = true};

            EditorGUILayout.BeginVertical(new GUIStyle("Box"));
            EditorGUILayout.LabelField(title, titleStyle);
            EditorGUILayout.LabelField(message, msgStyle);
            EditorGUILayout.EndVertical();
        }

        private void DrawSubItemContent(int summaryIndex,int itemIndex, int subItemIndex)
        {
            GUIStyle titleStyle = new GUIStyle("BoldTextField") { fontSize = 12, fontStyle = FontStyle.Bold, richText = true };

            SummarySubItem subItem = _curSummaryMap[summaryIndex].summaryItems[itemIndex].summarySubItems[subItemIndex];
            EditorGUILayout.BeginVertical(new GUIStyle("Box")); 
            subItem.subTitle = EditorGUILayout.TextField(new GUIContent("标题: "),subItem.subTitle, titleStyle);
            subItem.content = EditorGUILayout.TextArea(subItem.content);
            EditorGUILayout.EndVertical();
        }
    }
}